package com.wyw.learning.thread.atomic;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.LongAdder;

/**
 * 演示高并发场景下，LongAdder比AtomicLong性能好
 *      Adder 累加器 Java8引入，高并发下LongAdder比AtomicLong效率高，本质是空间换时间
 *      好处：在竞争激烈的时候，LongAdder吧不同线程对应到不同的cell上进行修改，降低了冲突的概率，是多段锁理念，提高了并发性
 *
 *      保证的是自己工作内存中的计数准确，每个线程会有自己的一个计数器，每次加法不会同步，不需要flush和refresh操作
 *      汇总阶段：
 *          引入了分段累加的概念，内部有一个base变量和一个Cell[]数组共同参与技术
 *              base变量：竞争不激烈，直接累加到变量上
 *              Cell[]数组：竞争计略，各个线程分散累加到自己的槽Cell[i]，计算了哈希值，最终的求和不会特别精确
 *
 *      对比AtomicLong和LongAdder
 *          在低争用下，AtomicLong和LongAdder这两个类具有相似的特征，但是和竞争激烈情况下，LongAdder的预期吞吐量要高很多，但是要消耗更多的空间
 *          LongAdder适合统计求和计数的场景 而且LongAdder基本只提供add方法，而AtomicLong还具有cas方法
 *
 *          LongAdder sum是线程安全的
 *
 * @author Mr Wu    yewen.wu.china@gmail.com
 * <p>
 * Update History:
 * Author        Time            Content
 */
public class LongAdderDemo {

    public static void main(String[] args) {
        LongAdder counter = new LongAdder();
        ExecutorService service = Executors.newFixedThreadPool(20);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            service.submit(new Task(counter));
        }
        service.shutdown();
        while (!service.isTerminated()) {

        }
        long end = System.currentTimeMillis();
        System.out.println(counter.sum());
        System.out.println("LongAdder耗时：" + (end - start));
    }

    private static class Task implements Runnable {

        private LongAdder counter;

        public Task(LongAdder counter) {
            this.counter = counter;
        }

        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                counter.increment();
            }
        }
    }
}
